<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      .classListDiv {
        width: 100px;
        height: 100px;
      }
      .classListRemove {
        background-color: #ccc;
      }
      .classListAdd {
        border: 5px solid black;
      }
    </style>
    <!-- js是解释型语言，逐行运行 -->
  </head>
  <body>
    <!-- 行内式的js -->
    <input type="button" value="点我" onclick="alert('惊喜')" />
    <div class="classListDiv classListRemove">看我的类名</div>
    <button class="classListBtn">切换类</button>
    <!-- 外部js文件 -->
    <script src="../js/js-basic.js"></script>
    <!-- 內嵌式的js -->
    <script>
      // 单行注释 ctrl + /
      /* 多行注释 shift + alt + a */

      /* 变量：用于存放数据的空间
              使用方法：
                  1. var 变量名; 声明一个变量
                  2. 变量名 = 值 赋值把值存入变量
                  3. var 变量名 = 值; 变量初始化(一步实现1、2)
                  4.集体声明变量，在变量之间加逗号，如 var a=9,b=9;
              特点：
                  1. 对同一个变量的赋值操作，以最后操作为准
                  2. 可以声明多个变量
                  3. 只声明不赋值，默认为undefined
                  4. 不声明不赋值，直接使用会报错
                  5. 不声明只赋值，可以使用，会变成全局变量
              命名规范：
                  1. 由字母 数字 _ ＄ 组成
                  2. 区分大小写
                  3. 不能数字开头
                  4. 不能为关键字，如 var
                  5. 需要有意义，人如其名
                  6. 驼峰命名法，首字母小写，后面单词的首字母大写，如myFirstName
       */

      /* 数据类型
            1. js的变量数据类型在声明的时候是不确定的，是在程序运行时根据变量等号右边的值确定的
            2. js是动态语言，数据类型是可以变化的
            3. 简单数据类型(值类型)：
                在存储时变量存储的是值本身,存放在栈中，直接开辟一个空间用于存放
                1) Number 数字型，包含整型和浮点型；js中八进制前面加 0，十六进制前面加 0x
                2) String 字符串型，由引号包含
                3) Boolean 布尔型，只有false和true两个值
                4) undefined 未定义数据类型，只声明不赋值就是该类型
                5) null 空值 返回的是一个空的对象object
                    所以可以将对象赋值为null
            4.typeof获取变量数据类型
            5.数据类型转换
            6.复杂数据类型（引用类型）:
                在存储时在栈中存储地址(引用),十六进制表示，地址指向存储在堆里的数据
                通过new关键字创建的对象，如Object、Array、Date等

        */

      // 1)Number 数字型
      console.log("------------------------");
      console.log("Number 数字型");
      // 最大值
      console.log("数字型最大值是" + Number.MAX_VALUE);
      // 最小值
      console.log("数字型最小值是" + Number.MIN_VALUE);
      // 无穷大 Infinity
      console.log("无穷大是" + Number.MAX_VALUE * 2);
      // 无穷小 -Infinity
      console.log("无穷小是" + -Number.MAX_VALUE * 2);
      // 非数字 NaN
      var unDefined;
      console.log(unDefined + 20);
      // isNaN(x)判断一个变量是否是非数字类型
      console.log("isNaN(233)判断233是否是非数字" + isNaN(233));

      // 2)String 字符串型
      console.log("------------------------");
      console.log("String 字符型");
      // 用单引号或者双引号包含,引号嵌套可以单引号嵌套双引号或者双引号嵌套单引号
      console.log('外单内"双"');
      console.log("外双内'单'");
      // 常用转义符
      // \n 换行 \\ 斜杠 \' 单引号 \" 双引号 \t tab缩进 \b 空格
      console.log("我要用\n换行");
      // str.length 字符串长度
      var str = "通过字符串的length属性获取其长度";
      console.log(str.length);
      // str1 + str2 字符串拼接
      console.log("字符串通过+号" + "拼接");
      // 拼接时只有有一个值是字符串型，结果就是字符串型
      var num = 666;
      console.log("字符串型" + num);

      // 3)Boolean 布尔型
      console.log("------------------------");
      console.log("Boolean 布尔型");
      // 只有false和true两个值
      // true参加运算相当于1
      console.log(true + 1);
      // fale参加运算相当于0
      console.log(false + 1);

      // 4)undefined 未定义数据类型
      console.log("------------------------");
      console.log("undefined 未定义数据类型");
      // 只声明不赋值变量时该变量为undefined
      // 4.typeof获取变量类型
      console.log(typeof unDefined);
      // 进行运算会输出NaN
      console.log(unDefined + 20);

      // 5)Null 空值
      console.log("------------------------");
      console.log("null 空值");
      var nullTest = null;
      console.log(typeof nullTest);

      // 5.数据类型转换
      console.log("------------------------");
      console.log("数据类型转换");

      // 5.1 转换为字符串型
      console.log("------------------------");
      console.log("转换为字符串型");
      // 5.1.1 变量.toString();
      var numToString_num = 10;
      var numToString_string = numToString_num.toString();
      console.log(typeof numToString_string);
      // 5.1.2 String(变量);
      console.log(typeof String(numToString_num));
      // 5.1.3 +号拼接字符串(常用)
      console.log(typeof (numToString_num + ""));

      // 5.2 转换为数字型
      console.log("------------------------");
      console.log("转换为数字型");
      // 转换为数字型的字符串型要求以数字开头，数字后的非数字会舍去
      // 5.2.1 parseInt(变量)(常用)
      // 该方法得到的数字为整型，浮点型数字会取整，不会四舍五入
      var stringToNum = "666";
      console.log(typeof parseInt(stringToNum));
      // 5.2.2 parseFloat(变量)(常用)
      // 该方法得到的数字为浮点型
      console.log(typeof parseFloat(stringToNum));
      // 5.2.3 Number(变量)
      console.log(typeof Number(stringToNum));
      // 5.2.4 算数运算符 - * / 不能用 + +会拼接字符串
      console.log(typeof (stringToNum * 2));

      // 5.3 转换为布尔型
      console.log("------------------------");
      console.log("转换为布尔型");
      // Boolean()
      // 代表空、否定的值会转换为false，如''、0、NaN、null、undefined;其他会转换为true
      console.log(Boolean(0));

      /* 运算符
           1.算术运算符 + - * / %
           2.递增和递减运算符 ++ --
           3.比较运算符
           4.逻辑运算符
           5.逻辑中断
           6.赋值运算符
           7.运算符优先级
       */
      console.log("------------------------");
      console.log("运算符");

      //  1.算术运算符 + - * / %
      console.log("------------------------");
      console.log("算术运算符");
      // + - * / 顾名思义；%是取余，余数为0意味着可以整除
      // 浮点数使用算术运算会有进制转换问题导致出错,谨慎使用
      console.log("3%5结果是" + (3 % 5));

      // 2.递增和递减运算符 ++ --
      console.log("------------------------");
      console.log("递增和递减运算符");
      // 前置自增,先加后返回
      console.log("前置自增++num结果是" + ++num);
      num--; // 前置自增和后置自增单独使用，效果一样
      // 后置自增，先返回后加
      console.log("后置自增num++结果是" + num++);
      console.log("后置自增num++后num是" + num);
      num--;

      // 3.比较运算符
      console.log("------------------------");
      console.log("比较运算符");
      // 浮点数不能直接拿来比较是否相等
      // <小于 | >大于 | >=大于等于 | <=小于等于 | ==等于(只看数值，不看数据类型) | !=不等于 | ===全等(数据类型也要相等) | !==不全等
      console.log("1 < 2的结果是" + (1 < 2));
      console.log("1 > 2的结果是" + (1 > 2));
      console.log("1 >= 2的结果是" + (1 >= 2));
      console.log("1 <= 2的结果是" + (1 <= 2));
      console.log("1 == '1'的结果是" + (1 == "1"));
      console.log("1 != '1'的结果是" + (1 != "1"));
      console.log("1 === '1'的结果是" + (1 === "1"));
      console.log("1 !== '1'的结果是" + (1 !== "1"));

      // 4.逻辑运算符 &&(与) ||(或) !(非)
      console.log("------------------------");
      console.log("逻辑运算符");
      // &&(与) 其两侧均为true输出true
      console.log("3 > 5 && 3 > 2 结果是" + (3 > 5 && 3 > 2));
      console.log("3 < 5 && 3 > 2 结果是" + (3 < 5 && 3 > 2));
      // ||(或)
      console.log("3 > 5 || 3 > 2 结果是" + (3 > 5 || 3 > 2));
      console.log("3 < 5 || 3 > 2 结果是" + (3 < 5 || 3 > 2));
      // !(非)
      console.log("!true 结果是" + !true);
      console.log("!false 结果是" + !false);

      // 5.逻辑中断：当多个表达式中左边的表达式可以确定结果时，不在运算右边的表达式
      console.log("------------------------");
      console.log("逻辑中断");
      // &&逻辑与左真返回右表达式，左假返回左表达式
      console.log("123 && 456 因为左真所以返回右表达式" + (123 && 456));
      console.log("0 && 456 因为左假所以返回左表达式" + (0 && 456));
      // ||逻辑或左真返回左表达式，左假返回右表达式
      console.log("123 || 456 因为左真所以返回左表达式" + (123 || 456));
      console.log("'' || 456 因为左假所以返回右表达式" + ("" || 456));
      // 逻辑中断会影响程序运行结果(重要)
      console.log("123 || num++因为左真所以返回左表达式" + (123 || num++));
      console.log("那么其右表达式是否运行");
      console.log("因为num++没有运行，所以num值为" + num);

      // 6.赋值运算符
      console.log("------------------------");
      console.log("赋值运算符");
      // =直接赋值
      var assignment = 10;
      console.log("=直接赋值后assignment=" + assignment);
      // +=先加后赋值
      assignment += 5; //相当于assignment = assignment + 5;
      console.log("+=5后assignment=" + assignment);
      // -=先减后赋值
      assignment -= 10; //相当于assignment = assignment - 10;
      console.log("-=10后assignment=" + assignment);
      // *=先乘后赋值
      assignment *= 2; //相当于assignment = assignment * 2;
      console.log("*= 2后assignment=" + assignment);
      // /=先除后赋值
      assignment /= 5; //相当于assignment = assignment / 5;
      console.log("/= 5后assignment=" + assignment);
      // %=先余后赋值
      assignment %= 3;
      console.log("%= 3后assignment=" + assignment);

      // 7.运算符优先级
      console.log("------------------------");
      console.log("运算符优先级");
      /* 1.小括号 （）
          2.一元运算符 先 ！ 后 ++ --
          3.算术运算符 先 * / % 后 + -
          4.关系运算符 > >= < <=
          5.相等运算符 == != === !==
          6.逻辑运算符 先 && 后 ||
          7.赋值运算符 =
          8.逗号运算符 ，
       */
      // 手动运算时可以先通过优先级低的分块，再一块块运算结果

      // 流程控制
      console.log("------------------------");
      console.log("流程控制");
      // 1.顺序流程控制
      // 上面的语句基本为顺序流程控制，程序会逐行运行

      // 2.分支流程控制
      // 2.1 分支流程控制if语句
      /*       var yearInput = prompt("请输入出生年份");
      if (yearInput == "" || isNaN(yearInput % 1)) {
        alert("请输入年份");
      } else if (
        (yearInput % 4 == 0 && yearInput % 100 != 0) ||
        yearInput % 400 == 0
      ) {
        alert(yearInput + "年是闰年");
      } else {
        alert(yearInput + "年不是闰年");
      } */
      // 2.1.0 三元表达式
      // 条件表达式 ？ 表达式1 ：表达式2
      // 如果条件为真，返回表达式1，否则返回表达式2
      var numIs666 = num == 666 ? true : false;
      console.log("当前num为666？" + numIs666);

      // 2.2 分支流程控制switch语句
      // switch(key)中的值如果与case后的值全等，执行该case中的语句，否则执行default中的语句
      // case中的语句要加break才会在执行后退出switch，否则会继续执行下一个case
      // switch中的值和case后的值要全等才会匹配上
      /*       var numSwitch = prompt("请输入1-3中的一个数字");
      switch (parseInt(numSwitch)) {
        case 1:
          alert("选择了1");
          break;
        case 2:
          alert("选择了2");
          break;
        case 3:
          alert("选择了3");
          break;
        default:
          alert("请正确选择");
          break;
      } */

      // 2.3 switch和if的区别
      /* 2.3.1 一般情况可以互相替代
         2.3.2 switch适用于case比较确定值的情况，if常用于范围判断
         2.3.3 switch判断符合条件后直接执行，if要将所有条件判断后执行符合条件的，所以switch一般效率较高
         2.3.4 switch适用于分支多的，if适用于分支少的
      */

      //3.循环流程控制
      // 3.1 for 循环
      /* 语法结构：
            for(初始化变量;条件表达式;操作表达式){循环体}
            初始化变量：声明一个变量，通常作为计数器使用
            条件表达式：结束循环条件，符合条件循环，不符合结束循环
            操作表达式：每次循环最后执行的代码，通常用于更新计数器变量
         执行过程：
            1.优先执行初始化变量，在该循环中只进行一次
            2.通过条件表达式判断，符合条件执行循环体，不符合结束循环
            3.执行操作表达式
            4.回到2继续
         循环嵌套:
            for(外层初始化变量;外层条件表达式;外层操作表达式){
              for(里层初始化变量;里层条件表达式;里层操作表达式){
                循环体
              }
            }
            里层的for循环可以看作外层for循环的循环体
            外层循环一次，里层循环全部
      */
      console.log("------------------------");
      console.log("for循环");
      var sum = 0;
      for (var i = 1; i <= 100; i++) {
        sum += i;
      }
      console.log("1加到100等于" + sum);

      // 循环嵌套案例
      console.log("九九乘法表");
      var multiplicationTable = "";
      for (var i = 1; i <= 9; i++) {
        for (var j = 1; j <= i; j++) {
          multiplicationTable += j + "*" + i + "=" + i + j + "\t";
        }
        multiplicationTable += "\n";
      }
      console.log(multiplicationTable);

      // 3.2 while 循环
      /* 语法结构：
            while (条件表达式) {
              循环体
            }
          特点：
            符合条件就循环
            while循环也需要初始化变量、计数器
            循环体内应有操作表达式进行计数器更新，防止死循环
      */
      console.log("------------------------");
      console.log("while循环");
      var numWhile = 1;
      while (numWhile <= 3) {
        console.log(numWhile);
        numWhile++;
      }

      // 3.3 do while 循环
      /* 语法结构：
            do {
              循环体
            }while(条件表达式)
          特点：
            与while循环不同，do while循环先执行一次循环体再判断条件，符合继续循环，否则退出循环
            do while循环体至少执行一次
      */
      console.log("------------------------");
      console.log("do while循环");
      var numDoWhile = 3;
      do {
        console.log(numDoWhile);
        numDoWhile--;
      } while (numDoWhile >= 1);

      // 4.continue和break关键字
      // 4.1 continue 退出本次循环，继续进行下一次循环
      console.log("------------------------");
      console.log("continue");
      for (var i = 1; i <= 5; i++) {
        if (i == 3) {
          continue;
        }
        console.log(i);
      }

      // 4.2 break  退出所有循环
      console.log("------------------------");
      console.log("break");
      for (var i = 1; i <= 5; i++) {
        if (i == 3) {
          break;
        }
        console.log(i);
      }

      // 数组 一组数据的集合
      /* 创建数组：
            1.new创建数组
            2.[]创建数组
          特点：
            1.数组中的数据以逗号分隔
            2.数组中的数据称为数组元素,数据类型不限
            3.数组名[索引号] 获取数组元素，索引号从0开始
            4.不存在数组中的数组元素，默认为undefined
          遍历：把数组元素从头到尾访问一遍
            for(var i=0;i<arr.length;i++){
              console.log(arr[i]);
            }
            通过for循环遍历数组，因为数组索引号从0开始，所以i也从0开始
          数组长度 数组名.length
            数组的长度为其数组元素个数，不是索引号
            该方法可以动态监测数组元素个数
          新增数组元素
            1.通过更改数组名.length的值
            2.修改索引号

       */
      console.log("------------------------");
      console.log("数组");
      // 创建数组
      var creatArr = new Array();
      // 数组元素的数据类型不限
      creatArr = ["星期天", 666, true, 233];
      // 通过更改数组名.length的值新增数组元素
      creatArr.length = 6;
      // 通过修改索引号新增数组元素
      creatArr[7] = 333;
      console.log(creatArr);
      console.log(creatArr.length);
      // 数组中不存在的数组元素为undefined
      console.log(creatArr[10]);

      // 求数组总和、平均值
      var sumArr = [2, 6, 1, 7, 4];
      var arrSum = 0;
      var arrAverage = 0;
      for (var i = 0; i < sumArr.length; i++) {
        arrSum += sumArr[i];
      }
      arrAverage = arrSum / sumArr.length;
      console.log(arrSum, arrAverage);

      // 冒泡排序
      console.log("------------------------");
      console.log("冒泡排序");
      var bubbleSortArr = [2, 6, 1, 7, 4];
      // 外层循环决定冒泡趟数
      for (var i = 0; i <= bubbleSortArr.length - 1; i++) {
        // 内层循环决定比较次数
        for (var j = 0; j <= bubbleSortArr.length - i - 1; j++) {
          if (bubbleSortArr[j] > bubbleSortArr[j + 1]) {
            var temp = bubbleSortArr[j];
            bubbleSortArr[j] = bubbleSortArr[j + 1];
            bubbleSortArr[j + 1] = temp;
          }
        }
      }
      console.log(bubbleSortArr);
      bubbleSortArr = [2, 6, 1, 7, 4];

      // 函数
      /* 函数就是封装了一段可以被重复执行调用的代码块
         使用方法：
            1.声明函数
              1.1 利用函数关键字定义函数（命名函数）:
              function 函数名(形参1,形参2...){
                函数体
                return 返回值
              }
              1.2 函数表达式（匿名函数）：
              var 变量名 = function(){}
              1.3 两者区别：
                    1.1调用时调用的是函数名
                    1.2调用的是变量名，该方法并没有定义函数名
            2.调用函数
            函数名(实参1,实参2...)
         特点：
            1.函数不调用不执行
            2.函数的参数不限个数，可以没有参数
            3.形参在声明函数的小括号里，实参在调用函数的小括号里
            4.实参和形参个数一致正常返回
            5.实参多于形参只会按形参个数取前几个
            6.实参少于形参时多余的形参定义为undefined
            7.函数可以调用另一个函数
          返回值格式：
            1.函数最终的结果需要返回给函数的调用者，通过return返回
            2.只要遇到可以使用的return就把结果返回给函数的调用者,return下面不会继续执行
            3.函数如果没有return返回，则返回undefined
      */
      console.log("------------------------");
      console.log("函数");
      // 求两个数中的最大值
      function getMax(num1, num2) {
        return num1 > num2 ? num1 : num2;
      }
      console.log(getMax(10, 13));

      // arguments使用
      /* 特点：
          1.只有函数才有arguments对象，在定义函数时就内置了arguments对象
          2.arguments对象里面存储了所以传递过来的实参
          3.arguments对象使用了伪数组，伪数组并不是真正的数组，它具有length属性，按照索引号方式存储，但是并没有真正数组的一些方法,如pop()、push()等
      */
      console.log("------------------------");
      console.log("argument使用");
      // 求最大值
      var argumentsGetMax = function () {
        var max = arguments[0];
        for (var i = 0; i < arguments.length; i++) {
          if (arguments[i] > max) {
            max = arguments[i];
          }
        }
        return max;
      };
      console.log(argumentsGetMax(5, 1, 9));

      // 作用域
      /* 概念：
            作用域就是变量在哪个范围内起作用
         目的：
            提高程序的可靠性，减少命名冲突
          分类:
            1.全局作用域：作用范围在整个script标签或js文件
            2.局部作用域（函数作用域）：作用范围在函数内部
          变量的作用域：
            1.全局变量：在全局作用域下的变量，只有浏览器关闭时销毁
              注：在函数中没有声明直接赋值的变量也是全局变量
            2.局部变量：在局部作用域下的变量，程序执行完毕就销毁
              注：函数的形参也是局部变量
          作用域链：
            内部函数访问外部函数的变量，采取的是就近原则的链式查找
          js引擎运行js步骤：
            1.预解析：
              1.1变量预解析（变量提升）：将所有的变量声明提升到当前作用域的最前面，不提升赋值操作
              1.2函数预解析（函数提升）：将所有的函数声明提升到当前作用域的最前面，不调用函数
            2.代码执行：经过预解析后，按照代码书写顺序从上往下执行
      */
      console.log("------------------------");
      console.log("作用域");
      // 预解析案例
      /* f1();
      console.log(c);
      console.log(b);
      console.log(a);
      function f1() {
        //该变量声明相当于var a=9;b=9;c=9;
        //其中只有a通过var声明是局部变量，b和c都是直接赋值，为全局变量
        var a = (b = c = 9);
        console.log(a);
        console.log(b);
        console.log(c);
      } */
      // 以上案例在经过js引擎预解析后的代码执行顺序如下
      /* function f1() {
        var a;
        a = b = c = 9;
        console.log(a);
        console.log(b);
        console.log(c);
      }
      f1();
      console.log(c);
      console.log(b);
      console.log(a); */

      // 对象
      /* 使用方法：
            1.创建对象：
              1.1利用对象字面量创建对象
                var 对象名 = {key1:value,key2:value...,keyn:function(){}}
                特点：
                  1）对象中的属性和方法采用键值对的形式定义
                  2）多个属性和方法中用逗号隔开
                  3）方法定义的函数为匿名函数
              1.2利用new Object创建对象
                var 对象名 = new Object();
                特点：
                  1）该方法定义对象中的属性和方法：
                      对象名.属性名 = 值;
                      对象名.方法名 = function(){};
                  2）多个属性和方法中用分号隔开
                  3）方法定义的函数为匿名函数
            2.调用对象
              2.1调用对象的属性：
                2.1.1对象名.属性名
                2.1.2对象名['属性名']
              2.2调用对象的方法
                对象名.方法名()
         构造函数:
            目的：
              创建对象时，里面的属性和方法大多相同，因此通过构造函数的方法封装对象以重复创建类似对象
            语法格式：
              function 构造函数名(形参){
                this.属性名 = 值;
                this.方法名 = function(){}
              }
            使用方法：
              new 构造函数名(实参);
              1.调用构造函数创建对象的过程称为对象的实例化
              2.new的执行过程：
                2.1在内存中创建一个新的空对象
                2.2让this指向这个新对象
                2.3执行构造函数中的代码，为这个新对象添加属性和方法
                2.4返回这个新对象（所以构造函数不需要return返回结果）
            特点：
              1.调用构造函数返回的是一个对象
              2.构造函数名首字母大写
              3.构造函数不需要return返回结果
              4.调用构造函数必须使用new
              5.构造函数的属性和方法前必须加this
              6.构造函数类似一个种类，对象是一个具体事物
         遍历对象：
            for in遍历对象：
              不能用for遍历对象
            语法格式：
              for(变量 in 对象){}
            特点：
              1.变量一般用k或key
              2.变量返回属性名
              3.对象名[变量]返回属性值
         分类：
            1.自定义对象:如上
            2.内置对象：详情看MDN
            3.浏览器对象
      */

      console.log("------------------------");
      console.log("对象");
      // 构造函数Dog
      function Dog(name, type, age, color) {
        this.name = name;
        this.type = type;
        this.age = age;
        this.color = color;
        this.bark = function () {
          console.log("汪汪汪");
        };
      }
      // 使用构造函数
      var keke = new Dog("可可", "阿拉斯加犬", 5, "棕红色");
      // 定义keke对象的方法
      keke.showMovie = function () {
        console.log("我是明星狗");
      };
      //遍历对象返回属性
      for (key in keke) {
        if (typeof keke[key] != "function") {
          console.log(key + ":" + keke[key]);
        }
      }
      //调用对象的方法
      keke.bark();
      keke.showMovie();

      // 内置对象
      console.log("------------------------");
      console.log("内置对象");
      // 1.Math数学对象
      /* 该方法会自动将字符串型转换为数字型，非数字返回NaN
         Math.abs(value) 绝对值方法
         Math.floor(value) 向下取整方法
         Math.ceil(value) 向上取整方法
         Math.round(value) 四舍五入方法
         Math.random() 随机数方法
      */
      console.log("------------------------");
      console.log("Math数学对象");
      console.log("Math.abs(value)绝对值方法");
      console.log(Math.abs(-1));
      console.log(Math.abs("-1"));
      console.log(Math.abs("xxx"));
      console.log("Math.floor(value)向下取整方法");
      console.log(Math.floor(1.1));
      console.log(Math.floor(1.5));
      console.log(Math.floor(1.9));
      console.log("Math.ceil(value)向上取整方法");
      console.log(Math.ceil(1.1));
      console.log(Math.ceil(1.5));
      console.log(Math.ceil(1.9));
      console.log("Math.round(vround)四舍五入方法");
      // .5会往大取整
      console.log(Math.round(1.1));
      console.log(Math.round(1.5));
      console.log(Math.round(1.9));
      console.log("Math.random() 随机数方法");
      //随机返回一个小数，0=<x<1
      console.log(Math.random());
      //返回两个数之间的随机整数
      function getRandom(min, max) {
        return Math.floor(Math.random() * (max - min + 1)) + min;
      }
      console.log(getRandom(1, 10));

      // 2.Date日期对象
      /* 特点：
          1.Date()是一个构造函数，必须使用new来调用
          2.如果没有参数返回当前系统的当前时间
          3.参数可以用数字型 2023,3,21;或者字符串型'2023-3-21'
      */
      console.log("------------------------");
      console.log("Date日期对象");
      // 调用Date日期对象
      var dateTest = new Date();
      console.log(dateTest);
      console.log(new Date(2023, 3, 21));
      console.log(new Date("2023-3-21"));
      //获取Date总的毫秒数（时间戳）
      //获得的毫秒数是距离1970年1月1号的毫秒数
      console.log(new Date().valueOf());
      console.log(new Date().getTime());
      //推荐使用+new Date()方法
      console.log(+new Date());
      //Date.now()方法是H5新增方法
      console.log(Date.now());
      // 格式化日期
      var year = dateTest.getFullYear(); //返回当前日期的年
      var month = dateTest.getMonth() + 1; //返回当前日期的月，会小一个月，所以要加1
      var dates = dateTest.getDate(); //返回当前日期的日
      var h = dateTest.getHours(); //返回当前日期的时
      h = h < 10 ? "0" + h : h; //
      var m = dateTest.getMinutes(); //返回当前日期的分
      m = m < 10 ? "0" + m : m;
      var s = dateTest.getSeconds(); //返回当前日期的秒
      s = s < 10 ? "0" + s : s;
      var arrWeek = [
        "星期日",
        "星期一",
        "星期二",
        "星期三",
        "星期四",
        "星期五",
        "星期六",
      ];
      var day = dateTest.getDay(); //返回当前日期是星期几，星期天为0，星期一至星期六为1-6
      console.log(
        "现在是" +
          year +
          "年" +
          month +
          "月" +
          dates +
          "日" +
          h +
          "时" +
          m +
          "分" +
          s +
          "秒" +
          "\t" +
          arrWeek[day]
      );
      //倒计时,具体代码在js-basic.js
      console.log(countDown("2023-3-22"));

      // 3.Array数组对象
      /* 创建数组的两种方法：
            1.利用数组字面量: var 数组名 = [];
            2.利用 new Array(): var 数组名 = new Array(); 括号中的值表示数组的长度
         检测是否为数组:
            1.数组名 instanceof Array
            2.Array.isArray(参数) H5新增
         添加数组元素：
            1.push() 在数组末尾添加数组元素
            2.unshift() 在数组头部添加数组元素
            3.特点：
                1.参数直接写数组元素,可以有多个
                2.操作完后返回的结果是新数组长度
                3.原数组会发生变化
         删除数组元素：
            1.pop() 删除数组最后一个元素
            2.shift() 删除数组第一个元素
            3.特点：
                1.一次只能删除一个数组元素
                2.直接使用，不需要参数
                3.操作完成后返回的结果是被删除的数组元素
                4.原数组会发生变化
          数组排序：
            1.翻转数组 数组名.reverse()
            2.冒泡排序 数组名.sort()
          获取数组元素索引:
            数组名.indexOf(数组元素,[查找开始的位置])
            特点：
              1.从头开始查找数组元素
              2.返回第一个满足条件的数组元素的索引号
              3.数组中不存在的返回-1
          转换为字符串：
            1.数组名.toString()
            2.数组名.join(分隔符),分隔符可以是数字、字母、空格、特殊符号等
          链接数组:
            数组1.concat(数组2,数组3...)
            多个数组组成新数组
          截取数组：
            数组名.slice(begin,end)
            返回包括从原数组[begin]到原数组[end-1]的数组元素的新数组
          删除数组元素：
            数组名.splice(第几个开始，删除个数)
            返回被删除项目的新数组，原数组会变化

      */
      console.log("------------------------");
      console.log("Array数组对象");
      //翻转数组,具体代码在js-basic.js
      console.log(myReverse([1, 2, 3]));

      var arrPush = [1, 2, 3];
      //添加数组元素
      console.log("原数组为" + arrPush);
      console.log(arrPush.push(4));
      console.log(arrPush.unshift(5));
      console.log("现数组为" + arrPush);
      //删除数组元素
      console.log("原数组为" + arrPush);
      console.log(arrPush.pop());
      console.log(arrPush.shift());
      console.log("现数组为" + arrPush);

      //数组排序
      //翻转数组
      console.log(arrPush.reverse());
      //冒泡排序
      console.log("排序前数组为" + bubbleSortArr);
      bubbleSortArr.sort(function (a, b) {
        //降序排序
        // return b - a;
        // 升序排序
        return a - b;
      });
      console.log("排序后数组为" + bubbleSortArr);

      //获取数组元素索引
      var arrIndex = ["芜湖", "起飞", "6啊", "兄弟"];
      console.log(arrIndex.indexOf("芜湖", [0]));
      //数组去重,具体代码在js-basic.js
      console.log(unique(["a", "a", "b", 1, 1]));

      // 转换为字符串
      var arrToString = ["芜湖", "起飞", "6啊", "兄弟"];
      var arrToString2 = ["芜湖", "起飞", "6啊", "兄弟"];
      console.log(arrToString.toString());
      console.log(arrToString2.join("!"));

      // 链接数组
      var arrConcat = [1, 2, 3];
      var arrConcat1 = [true];
      var arrConcat2 = ["优秀"];
      console.log(arrConcat.concat(arrConcat1, arrConcat2));

      // 截取数组
      var arrSlice = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
      console.log(arrSlice.slice(1, 3));

      // 删除数组元素
      var arrSplice = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
      console.log(arrSplice.splice(2, 3));
      console.log(arrSplice);

      // 4.字符串对象
      /* 注：因为字符串的不可变性，不要大量拼接字符串
         根据字符返回位置:
            字符串名.indexOf('要查找字符',[查找开始的位置])
          根据位置返回字符：
            1.字符串名.charAt(index)
            2.字符串名[index] H5新增
            3.字符串名.charCodeAt(index)
          字符串操作:
            1.字符串.concat('字符串1','字符串2'....) 拼接字符串
            2.字符串.substr('开始位置'，'个数'') 截取字符串
              个数省略默认截取到最后一个字符
            3.字符串.slice(start,end) 截取字符串
              end位置取不到，可以用负值，负值从后往前减小
            4.字符串.substring(start,end) 截取字符串
              end位置取不到，不能取负值
            5.字符串.replace('被替换的字符','替换为的字符') 替换字符
              只会替换第一个字符
            6.字符串.split('分隔符') 转换为数组
              根据分隔符划分数组元素
              没有匹配的分隔符就将整个字符串作为一个数组元素
              分隔符可以是数字、字母、空格、特殊符号
              分隔符不会保存到数组中
            7.toUpperCase() 转换为大写
            8.toLowerCase() 转换为小写
            */
      console.log("------------------------");
      console.log("字符串对象");
      // 根据字符返回位置
      var strIndexOf = "虎！天王盖地虎，宝塔镇河妖。";
      console.log(strIndexOf.indexOf("虎", [1]));

      // 根据位置返回字符
      console.log(strIndexOf.charAt(3));
      console.log(strIndexOf[4]);
      //返回相应索引号的字符ASCII码值
      console.log(strIndexOf.charCodeAt(1));

      // 字符串操作
      // concat拼接字符串
      var strConcat = "233";
      var strConcat1 = "666";
      console.log(strConcat.concat(strConcat1));
      // substr截取字符串
      var strSubstr = "123456789";
      console.log(strSubstr.substr(1, 3));
      //slice截取字符串
      console.log(strSubstr.slice(-9, -1));
      //substring截取字符串
      console.log(strSubstr.substring(1, 3));
      //replace替换字符
      var strReplace = "aaa";
      console.log(strReplace.replace("a", "b"));
      //split转换为数组
      var strSplit = "a%Bcde%fg";
      console.log(strSplit.split("%"));
      // toUpperCase() 转换为大写
      console.log(strSplit.toUpperCase());
      // toLowerCase() 转换为小写
      console.log(strSplit.toLowerCase());

      console.log("------------------------");
      // 立即执行函数
      console.log("立即执行函数");
      /*不用额外调用直接执行的函数
        写法： 
         1.(function(){})()
         2.(function(){}())
        特点：
         1.可以传递参数，声明函数
         2.第二个小括号看作调用函数
         3.函数内变量都是局部变量 */
      (function sumNow(a, b) {
        console.log(a + b);
      })(1, 2);
      (function () {
        console.log("我执行了");
      })();
      console.log("------------------------");
      // classList属性
      console.log("classList属性操作");
      var classListDiv = document.querySelector(".classListDiv");
      console.log(classListDiv.classList);
      // 添加类名 element.classList.add()
      classListDiv.classList.add("classListAdd");
      //删除类名 element.classList.remove()
      classListDiv.classList.remove("classListRemove");
      //切换类 element.classList.toggle()
      var classListBtn = document.querySelector(".classListBtn");
      classListBtn.addEventListener("click", function () {
        classListDiv.classList.toggle("classListRemove");
      });
      console.log("------------------------");
      // prompt 浏览器弹出输入框
      // var number = prompt("请输入数字");

      // alert 浏览器弹出警示框
      // alert(number);

      // console 控制台输出
      // 可以输出变量，想输出多个变量用逗号隔开
      console.log("內嵌式js正在运行");
    </script>
  </body>
</html>
